From 328282d3eefaa10131b083822e22918718efab90 Mon Sep 17 00:00:00 2001 From: Dirk Brenken Date: Fri, 28 Mar 2025 08:00:58 +0100 Subject: [PATCH] luci-app-banIP: sync with release 1.5.5-1 * added a geoIP Map to show home IPs and potential attacker IPs on a leafletjs based map, see readme for details Signed-off-by: Dirk Brenken --- .../luci-static/resources/view/banip/map.html | 118 +++++++++++++ .../resources/view/banip/overview.js | 6 +- .../resources/view/banip/setreport.js | 164 ++++++++++++------ .../usr/share/rpcd/acl.d/luci-app-banip.json | 7 +- 4 files changed, 235 insertions(+), 60 deletions(-) create mode 100644 applications/luci-app-banip/htdocs/luci-static/resources/view/banip/map.html diff --git a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/map.html b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/map.html new file mode 100644 index 0000000000..b7528aced9 --- /dev/null +++ b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/map.html @@ -0,0 +1,118 @@ + + + + + banIP Map + + + + + + + + +
+ + + + + + \ No newline at end of file diff --git a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/overview.js b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/overview.js index f2aa300f1d..35a258a5b1 100644 --- a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/overview.js +++ b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/overview.js @@ -275,7 +275,6 @@ return view.extend({ o.value('uclient-fetch'); o.value('wget'); o.value('curl'); - o.value('aria2c'); o.optional = true; o.retain = true; @@ -487,6 +486,11 @@ return view.extend({ o = s.taboption('adv_set', form.Flag, 'ban_nftcount', _('Set Element Counter'), _('Enable nft counter for every Set element.')); o.rmempty = true; + o = s.taboption('adv_set', form.Flag, 'ban_map', _('Enable GeoIP Map'), _('Enable a GeoIP Map with suspicious Set elements. This requires external requests to get the map tiles and geolocation data.')); + o.depends('ban_nftcount', '1'); + o.optional = true; + o.rmempty = true; + o = s.taboption('adv_set', form.ListValue, 'ban_blockpolicy', _('Inbound Block Policy'), _('Drop packets silently or actively reject Inbound traffic.')); o.value('drop', _('drop')); o.value('reject', _('reject')); diff --git a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/setreport.js b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/setreport.js index f4a2e5b87b..8e9f3eaaeb 100644 --- a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/setreport.js +++ b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/setreport.js @@ -2,6 +2,7 @@ 'require view'; 'require fs'; 'require ui'; +'require uci'; /* button handling @@ -47,41 +48,41 @@ function handleAction(report, ev) { document.getElementById('result').textContent = 'The search is running, please wait...'; return L.resolveDefault(fs.exec_direct('/etc/init.d/banip', ['search', ip])).then(function (res) { let result = document.getElementById('result'); - if (res) { - result.textContent = res.trim(); - } else { - result.textContent = _('No Search results!'); - } + result.textContent = res.trim(); document.getElementById('search').value = ''; }) } document.getElementById('search').focus(); }) - }, _('Search')) + }, _('Search IP')) ]) ]); document.getElementById('search').focus(); } - if (ev === 'survey') { - let content, selectOption; + if (ev === 'content') { + let content, selectOption, errMsg; if (report[1]) { try { content = JSON.parse(report[1]); } catch (e) { content = ""; - ui.addNotification(null, E('p', _('Unable to parse the ruleset file!')), 'error'); + if (!errMsg) { + errMsg = true; + return ui.addNotification(null, E('p', _('Unable to parse the ruleset file!')), 'error'); + } } } else { - content = ""; + return; } selectOption = [E('option', { value: '' }, [_('-- Set Selection --')])]; - for (let i = 0; i < Object.keys(content.nftables).length; i++) { - if (content.nftables[i].set && content.nftables[i].set.name !== undefined && content.nftables[i].set.table !== undefined && content.nftables[i].set.table === 'banIP') { - selectOption.push(E('option', { 'value': content.nftables[i].set.name }, content.nftables[i].set.name)); - } - } - L.ui.showModal(_('Set Survey'), [ + Object.keys(content.nftables) + .filter(key => content.nftables[key].set?.name && content.nftables[key].set.table === 'banIP') + .sort((a, b) => content.nftables[a].set.name.localeCompare(content.nftables[b].set.name)) + .forEach(key => { + selectOption.push(E('option', { 'value': content.nftables[key].set.name }, content.nftables[key].set.name)); + }) + L.ui.showModal(_('Set Content'), [ E('p', _('List the elements of a specific banIP-related Set.')), E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, [ E('label', { 'class': 'cbi-input-select', 'style': 'padding-top:.5em', 'id': 'run' }, [ @@ -113,43 +114,74 @@ function handleAction(report, ev) { 'click': ui.createHandlerFn(this, function (ev) { let set = document.getElementById('set').value; if (set) { - document.getElementById('result').textContent = 'The survey is running, please wait...'; - return L.resolveDefault(fs.exec_direct('/etc/init.d/banip', ['survey', set])).then(function (res) { + document.getElementById('result').textContent = 'Collecting Set content, please wait...'; + return L.resolveDefault(fs.exec_direct('/etc/init.d/banip', ['content', set])).then(function (res) { let result = document.getElementById('result'); - if (res) { - result.textContent = res.trim(); - } else { - result.textContent = _('No Search results!'); - } + result.textContent = res.trim(); document.getElementById('set').value = ''; }) } document.getElementById('set').focus(); }) - }, _('Survey')) + }, _('Show Content')) ]) ]); document.getElementById('set').focus(); } + if (ev === 'map') { + let md = L.ui.showModal(null, [ + E('div', { id: 'mapModal', + style: 'position: relative;' }, [ + E('iframe', { + id: 'mapFrame', + src: L.resource('view/banip/map.html'), + style: 'width: 100%; height: 80vh; border: none;' + }), + ]), + E('div', { 'class': 'right' }, [ + E('button', { + 'class': 'btn cbi-button', + 'click': function() { + L.hideModal(); + sessionStorage.clear(); + } + }, _('Cancel')), + ' ', + E('button', { + 'class': 'btn cbi-button-action', + 'click': ui.createHandlerFn(this, function (ev) { + let iframe = document.getElementById('mapFrame'); + iframe.contentWindow.location.reload(); + }) + }, _('Map Reset')) + ]) + ]); + md.style.maxWidth = '90%'; + document.getElementById('mapModal').focus(); + } } return view.extend({ load: function () { return Promise.all([ L.resolveDefault(fs.exec_direct('/etc/init.d/banip', ['report', 'json']), ''), - L.resolveDefault(fs.exec_direct('/usr/sbin/nft', ['-tj', 'list', 'table', 'inet', 'banIP']), '') + L.resolveDefault(fs.exec_direct('/usr/sbin/nft', ['-tj', 'list', 'sets']), ''), + uci.load('banip') ]); }, render: function (report) { - let content, rowSets, tblSets; + let content, rowSets, tblSets, notMsg, errMsg; if (report[0]) { try { content = JSON.parse(report[0]); } catch (e) { content = ""; - ui.addNotification(null, E('p', _('Unable to parse the report file!')), 'error'); + if (!errMsg) { + errMsg = true; + ui.addNotification(null, E('p', _('Unable to parse the report file!')), 'error'); + } } } else { content = ""; @@ -166,68 +198,70 @@ return view.extend({ ]) ]); - if (content.sets) { + if (content[0] && content[0].sets) { let cnt1, cnt2; - Object.keys(content.sets).forEach(function (key) { - cnt1 = content.sets[key].cnt_inbound ? ': (' + content.sets[key].cnt_inbound + ')' : ''; - cnt2 = content.sets[key].cnt_outbound ? ': (' + content.sets[key].cnt_outbound + ')' : ''; + + Object.keys(content[0].sets).sort().forEach(function (key) { + cnt1 = content[0].sets[key].cnt_inbound ? ': (' + content[0].sets[key].cnt_inbound + ')' : ''; + cnt2 = content[0].sets[key].cnt_outbound ? ': (' + content[0].sets[key].cnt_outbound + ')' : ''; rowSets.push([ E('em', key), - E('em', { 'style': 'padding-right: 20px' }, content.sets[key].cnt_elements), - E('em', content.sets[key].inbound + cnt1), - E('em', content.sets[key].outbound + cnt2), - E('em', content.sets[key].port), - E('em', content.sets[key].set_elements) + E('em', { 'style': 'padding-right: 20px' }, content[0].sets[key].cnt_elements), + E('em', content[0].sets[key].inbound + cnt1), + E('em', content[0].sets[key].outbound + cnt2), + E('em', content[0].sets[key].port), + E('em', content[0].sets[key].set_elements.join(", ")) ]); }); rowSets.push([ - E('em', { 'style': 'font-weight: bold' }, content.sum_sets), - E('em', { 'style': 'font-weight: bold; padding-right: 20px' }, content.sum_cntelements), - E('em', { 'style': 'font-weight: bold' }, content.sum_setinbound + ' (' + content.sum_cntinbound + ')'), - E('em', { 'style': 'font-weight: bold' }, content.sum_setoutbound + ' (' + content.sum_cntoutbound + ')'), - E('em', { 'style': 'font-weight: bold' }, content.sum_setports), - E('em', { 'style': 'font-weight: bold' }, content.sum_setelements) + E('em', { 'style': 'font-weight: bold' }, content[0].sum_sets), + E('em', { 'style': 'font-weight: bold; padding-right: 20px' }, content[0].sum_cntelements), + E('em', { 'style': 'font-weight: bold' }, content[0].sum_setinbound + ' (' + content[0].sum_cntinbound + ')'), + E('em', { 'style': 'font-weight: bold' }, content[0].sum_setoutbound + ' (' + content[0].sum_cntoutbound + ')'), + E('em', { 'style': 'font-weight: bold' }, content[0].sum_setports), + E('em', { 'style': 'font-weight: bold' }, content[0].sum_setelements) ]); } cbi_update_table(tblSets, rowSets); - return E('div', { 'class': 'cbi-map', 'id': 'map' }, [ + return E('div', { 'class': 'cbi-map', 'id': 'cbimap' }, [ E('div', { 'class': 'cbi-section' }, [ - E('p', _('This tab shows the last generated Set Report, press the \'Refresh\' button to get a new one.')), + E('p', _('This report shows the latest NFT Set statistics, press the \'Refresh\' button to get a new one. \ + You can also display the specific content of Sets, search for suspicious IPs and finally, these IPs can also be displayed on a map.')), E('p', '\xa0'), E('div', { 'class': 'cbi-value' }, [ E('div', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;width:230px;font-weight:bold;' }, _('Timestamp')), - E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-bottom:-5px;color:#37c;font-weight:bold;' }, content.timestamp || '-') + E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-bottom:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.timestamp || '-') ]), E('hr'), E('div', { 'class': 'cbi-value' }, [ E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;width:230px;font-weight:bold;' }, _('blocked syn-flood packets')), - E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content.sum_synflood || '-') + E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.sum_synflood || '-') ]), E('div', { 'class': 'cbi-value' }, [ E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;width:230px;font-weight:bold;' }, _('blocked udp-flood packets')), - E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content.sum_udpflood || '-') + E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.sum_udpflood || '-') ]), E('div', { 'class': 'cbi-value' }, [ E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;width:230px;font-weight:bold;' }, _('blocked icmp-flood packets')), - E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content.sum_icmpflood || '-') + E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.sum_icmpflood || '-') ]), E('div', { 'class': 'cbi-value' }, [ E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;width:230px;font-weight:bold;' }, _('blocked invalid ct packets')), - E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content.sum_ctinvalid || '-') + E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.sum_ctinvalid || '-') ]), E('div', { 'class': 'cbi-value' }, [ E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;width:230px;font-weight:bold;' }, _('blocked invalid tcp packets')), - E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content.sum_tcpinvalid || '-') + E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.sum_tcpinvalid || '-') ]), E('hr'), E('div', { 'class': 'cbi-value' }, [ E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;width:230px;font-weight:bold;' }, _('auto-added IPs to allowlist')), - E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content.autoadd_allow || '-') + E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.autoadd_allow || '-') ]), E('div', { 'class': 'cbi-value' }, [ E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;width:230px;font-weight:bold;' }, _('auto-added IPs to blocklist')), - E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content.autoadd_block || '-') + E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.autoadd_block || '-') ]) ]), E('br'), @@ -242,9 +276,31 @@ return view.extend({ 'class': 'btn cbi-button cbi-button-apply', 'style': 'float:none;margin-right:.4em;', 'click': ui.createHandlerFn(this, function () { - return handleAction(report, 'survey'); + if (uci.get('banip', 'global', 'ban_nftcount') !== '1' || uci.get('banip', 'global', 'ban_map') !== '1') { + if (!notMsg) { + notMsg = true; + return ui.addNotification(null, E('p', _('GeoIP Map is not enabled!')), 'info'); + } + } + if (content[1] && content[1].length > 1) { + sessionStorage.setItem('mapData', JSON.stringify(content[1])); + return handleAction(report, 'map'); + } + else { + if (!notMsg) { + notMsg = true; + return ui.addNotification(null, E('p', _('No GeoIP Map data!')), 'info'); + } + } + }) + }, [_('Map...')]), + E('button', { + 'class': 'btn cbi-button cbi-button-apply', + 'style': 'float:none;margin-right:.4em;', + 'click': ui.createHandlerFn(this, function () { + return handleAction(report, 'content'); }) - }, [_('Set Survey...')]), + }, [_('Set Content...')]), E('button', { 'class': 'btn cbi-button cbi-button-apply', 'style': 'float:none;margin-right:.4em;', diff --git a/applications/luci-app-banip/root/usr/share/rpcd/acl.d/luci-app-banip.json b/applications/luci-app-banip/root/usr/share/rpcd/acl.d/luci-app-banip.json index 4abe405f82..a572c77621 100644 --- a/applications/luci-app-banip/root/usr/share/rpcd/acl.d/luci-app-banip.json +++ b/applications/luci-app-banip/root/usr/share/rpcd/acl.d/luci-app-banip.json @@ -42,7 +42,7 @@ "/usr/sbin/logread -e banIP/": [ "exec" ], - "/usr/sbin/nft -tj list table inet banIP": [ + "/usr/sbin/nft -tj list sets": [ "exec" ], "/etc/init.d/banip stop": [ @@ -60,14 +60,11 @@ "/etc/init.d/banip search [A-Za-z0-9:.]*": [ "exec" ], - "/etc/init.d/banip survey [A-Za-z0-9]*": [ + "/etc/init.d/banip content [A-Za-z0-9]*": [ "exec" ], "/etc/init.d/banip status": [ "exec" - ], - "/etc/init.d/banip lookup": [ - "exec" ] }, "uci": [ -- 2.30.2